home *** CD-ROM | disk | FTP | other *** search
- {
- From: dmurdoch@mast.queensu.ca (Duncan Murdoch)
- >
- >Anyhow, what this program is doing (among other things) is reading data from
- >an ASCII file when commanded to, one line at a time, and plotting it on the
- >screen. My problem is, when you return to the main menu, a bit of the RAM
- >has been used. If you call up a couple of plots in a row, eventually you
- >run out of RAM and crash. And I'm having a devil of a time trying to figure
- >where the memory is going.
-
- This is one of the harder kinds of error to track down. The way I do it is
- as follows:
-
- 1. Throughout program development, I use a debugging unit that warns me if
- anything is left on the heap when the program terminates. If there is, I
- immediately track it down and fix it. The error is probably in the new
- part, and that helps to find it.
-
- 2. To prevent errors, I program in a very structured way: every allocation
- has a matching de-allocation, preferable within a dozen or two lines of
- it so they're both on screen at once and I can see that they match.
-
- 3. If the preventive methods don't work, I have to track down the bugs. I
- have a routine that can print heap usage when I want. I print all the heap
- that's used at the end of the program (should be none!), and try to
- recognize where the stuff came from. If it's strings, it's easy, but if
- it's binary data, it's hard. If necessary I trace through the program until
- I see one of those parts get allocated.
-
- I've attached my heap routine below, but it won't compile for you without a
- few utility routines from TurboPower's Object Professional library (and
- some others of mine). Hopefully it'll still be useful for you and you can
- write the other parts yourself.
-
- Duncan Murdoch
- }
- unit heap;
- { This unit does integrity checks on the TP 6.0 heap }
-
- interface
-
- uses standard,opinline,opstring,dump;
-
- function heapokay:boolean;
-
- procedure showfreelist(var where:text;msg:string);
- { Prints the free list }
-
- procedure showheapused(var where:text;msg:string);
- { Prints the heap usage }
-
- type
- PFreeRec = ^TFreeRec;
- TFreeRec = record
- next: PFreeRec;
- size: Pointer;
- end;
-
-
- implementation
-
- function Ordered(p1,p2:pointer):boolean;
- { Tests whether p1 <= p2 }
- begin
- Ordered := PtrToLong(p1) <= PtrToLong(p2);
- end;
-
- function Normed(p:pointer):boolean;
- { Checks whether p is a normalized pointer }
- begin
- case ofs(p^) of
- 0..$F : Normed := true;
- else Normed := false;
- end;
- end;
-
- function heapokay:boolean;
-
- procedure error(msg:string);
- begin
- writeln(stderr,msg);
- heapokay := false;
- halt(99);
- end;
-
- type
- PFreeRec = ^TFreeRec;
- TFreeRec = record
- next: PFreeRec;
- size: Pointer;
- end;
- var
- FreeRec : PFreeRec;
- begin
- if not Normed(HeapOrg) then
- error('HeapOrg bad!');
- if not Normed(FreeList) then
- error('FreeList bad!');
- if not Normed(HeapPtr) then
- error('HeapPtr bad!');
- if not Normed(HeapEnd) then
- error('HeapEnd bad!');
-
- if not Ordered(HeapOrg,FreeList) then
- error('HeapOrg > FreeList');
- if not Ordered(FreeList,HeapPtr) then
- error('FreeList > HeapPtr');
- if not Ordered(HeapPtr,HeapEnd) then
- error('HeapPtr > HeapEnd');
-
- FreeRec := FreeList;
- while PtrToLong(FreeRec) < PtrToLong(HeapPtr) do { Walk the free list }
- begin
- if not Normed(FreeRec^.next) then
- error('Bad next in free record '+HexPtr(FreeRec));
- if not ordered(FreeRec,FreeRec^.next) then
- error('self > next in free record '+HexPtr(FreeRec));
- if not ordered(AddLongToPtr(FreeRec,PtrToLong(FreeRec^.size)),
- FreeRec^.next) then
- error('Bad size in free record '+HexPtr(FreeRec));
- if FreeRec = FreeRec^.Next then
- error('Self pointer in free record '+HexPtr(FreeRec));
- FreeRec := FreeRec^.Next;
- end;
- if FreeRec <> HeapPtr then
- error('Bad last free block');
-
- heapokay := true;
- end;
-
- function addtopointer(p:pointer;incr:longint):pointer;
- { Adds increment to pointer, only normalizes if necessary }
- begin
- if ofs(p^) + incr > 65535 then
- addtopointer := AddLongToPtr(p,incr)
- else
- addtopointer := AddWordToPtr(p,incr);
- end;
-
- procedure showfreelist(var where:text;msg:string);
- { Prints the free list }
- var
- FreePtr : PFreerec;
- Free,Total:longint;
- begin
- writeln(where,msg);
- writeln(where,' Start Stop Size free');
-
- FreePtr := PFreeRec(@FreeList);
- Total := 0;
- repeat
- Free:=PtrToLong(Freeptr^.Size);
- inc(Total,Free);
- if Free <> 0 then
- writeln(where, HexPtr(FreePtr), ' ', HexPtr(AddToPointer(FreePtr,Free)),
- ' ',Free:6);
- FreePtr := FreePtr^.next;
- until FreePtr = HeapPtr;
- Free := PtrDiff(HeapEnd,HeapPtr);
- inc(Total,Free);
- writeln(where, HexPtr(HeapPtr), ' ', HexPtr(HeapEnd),
- ' ',Free:6);
- writeln(where, 'Total':8,'':14, Total:6);
- end;
-
- procedure showheapused(var where:text;msg:string);
- { Prints what's been used on the heap }
- var
- FreePtr : PFreerec;
- UsedPtr : Pointer;
- Used : longint;
- Total: longint;
- begin
- writeln(where,msg);
- writeln(where,' Start Stop Size used Data');
-
- FreePtr := FreeList;
- UsedPtr := HeapOrg;
- total := 0;
- while FreePtr <> HeapPtr do
- begin
- Used := PtrDiff(UsedPtr,FreePtr);
- inc(Total,Used);
- if used <> 0 then
- begin
- write(where, HexPtr(UsedPtr), ' ', HexPtr(AddToPointer(UsedPtr,Used)),
- ' ',Used:6,' ');
- dumpbothshort(where, UsedPtr^, 0, 8);
- end;
-
- UsedPtr := AddLongToPtr(FreePtr,PtrToLong(FreePtr^.size));
- if FreePtr <> HeapPtr then
- FreePtr := FreePtr^.next;
- end;
- Used := PtrDiff(HeapPtr,UsedPtr);
- inc(Total,used);
- if used <> 0 then
- begin
- write(where, HexPtr(UsedPtr), ' ', HexPtr(AddToPointer(UsedPtr,Used)),
- ' ',Used:6,' ');
- dumpbothshort(where, UsedPtr^, 0,8);
- end;
- writeln(where, 'Total':8,'':14, Total:6);
- end;
-
-
- end.
-